package belf.migrate.api.taskconf.typemapping;

import belf.migrate.api.table.schema.ColumnMetaData;
import belf.migrate.api.taskconf.TaskConf;

import java.sql.Types;
import java.util.List;
import java.util.function.Predicate;

/**
 * 检查源端字段是否匹配了库级或表级的映射
 */
public class TypeMappingChecker {

    /**
     * 检查是否有表一级的字段类型映射，如果有，返回自定义类型映射的字符串；如果没有，返回空字符串""
     * @param taskConf
     * @param columnMetaData
     * @return
     */
    public static String tableMapping(TaskConf taskConf, ColumnMetaData columnMetaData) {
        List<FieldTypeMapping> fieldTypeMappings = taskConf.getTableTypeMappings().get(columnMetaData.getTableName());
        if (null == fieldTypeMappings) {
            return "";
        }

        StringBuilder sb = new StringBuilder();
        for (FieldTypeMapping fieldTypeMapping: fieldTypeMappings) {
            FieldType sink = fieldTypeMapping.getSink();
            if (fieldTypeMapping.getSource().getName().equalsIgnoreCase(columnMetaData.getColumnName())
                    && sink != null) {
                DataType dataType = sink.getDataType();
                checkSinkDataType(dataType, sb);
            }
        }

        return sb.toString();
    }

    /**
     * 检查是否有库一级的字段类型映射，如果有，返回自定义数据类型映射的字符串；如果没有，返回空字符串""
     * @param taskConf
     * @param columnMetaData
     * @return
     */
    public static String databaseMapping(TaskConf taskConf, ColumnMetaData columnMetaData) {
        List<DataTypeMapping> dataTypeMappings = taskConf.getDataTypeMappings();
        if (null == dataTypeMappings) {
            return "";
        }

        StringBuilder sb = new StringBuilder();
        for (DataTypeMapping dataTypeMapping: dataTypeMappings) {
            if (dataTypeMapping.getSource().getTypeName().equalsIgnoreCase(columnMetaData.getColumnTypeName())) {
                DataType dataType = dataTypeMapping.getSink();
                checkSinkDataType(dataType, sb);
            }
        }

        return sb.toString();
    }

    /**
     * 处理类型及其长度,构造目标端的字段类型
     * @param dataType 用户自定义的数值类型
     * @param sb 接收类型构造结果的StringBuilder
     */
    private static void checkSinkDataType(DataType dataType, StringBuilder sb) {
        sb.append(dataType.getTypeName());
        if (dataType.getLength() > 0) { //变长字符串或字节类型
            sb.append('(' + dataType.getLength() + ')');
        } else if (dataType.getPrecision() > 0) { //数值类型
            if (dataType.getScale() > 0) { //带有精度[和标度]的数值类型
                sb.append('(');
                sb.append(dataType.getPrecision());
                sb.append(',');
                sb.append(dataType.getScale());
                sb.append(')');
            } else {                       //只有精度，没有指定标度
                sb.append('(' + dataType.getPrecision() + ')');
            }
        } else if (dataType.getTimePrecision() > 0) { //指定精度的时间类型
            sb.append('(' + dataType.getTimePrecision() + ')');
        }
    }
}
